#include "gologic.h"
#include <QtGlobal>

GoLogic::GoLogic(int boardSize, QObject* parent)
    : QObject(parent), m_size(boardSize), m_board(boardSize * boardSize, Color::Empty) {
    reset();
}

void GoLogic::reset() {
    m_board.fill(Color::Empty);
    m_history.clear();
    m_history.append(m_board);
    m_blackCaps = m_whiteCaps = 0;
    m_lastCapture = QPoint(-1, -1);
    m_isBlackTurn = true; // 重置回合为黑子先手
    emit boardChanged();
    emit capturedChanged(0, 0);
    emit turnChanged(); // 发出回合变更信号
}

bool GoLogic::playStone(int r, int c, bool black) {
    // 如果使用了指定颜色的接口，则直接使用指定颜色
    if (black != m_isBlackTurn) {
        // 如果指定的颜色与当前回合不符，仍然允许落子（保持向后兼容）
        // 但不切换回合状态
        bool result = playStone(r, c, black, false); // 不切换回合
        return result;
    }
    return playStone(r, c, black, true); // 切换回合
}

// 新增内部方法，包含回合切换逻辑
bool GoLogic::playStone(int r, int c, bool black, bool doSwitchTurn) {
    if (!inBounds(r, c)) return false;
    int idx = index(r, c);
    if (m_board[idx] != Color::Empty) return false;

    Color col = black ? Color::Black : Color::White;
    Color opp = black ? Color::White : Color::Black;

    m_board[idx] = col;

    // 提对方无气子
    bool captured = false;
    for (const auto& [dr, dc] : {QPoint(1,0), QPoint(-1,0), QPoint(0,1), QPoint(0,-1)}) {
        int nr = r + dr, nc = c + dc;
        if (!inBounds(nr, nc)) continue;
        if (m_board[index(nr, nc)] == opp) {
            QSet<int> vis;
            if (!hasLiberty(nr, nc, opp, vis)) {
                removeGroup(nr, nc, opp);
                captured = true;
            }
        }
    }
    // 简单劫：刚提的单一位置不能马上回提
    if (captured && m_lastCapture == QPoint(r, c)) {
        m_board = m_history.last(); // 回滚
        return false;
    }

    // 自杀判断
    QSet<int> vis;
    if (!hasLiberty(r, c, col, vis)) {
        m_board = m_history.last();
        return false;
    }

    // 记录历史
    m_history.append(m_board);
    if (m_history.size() > 500) m_history.pop_front(); // 防内存爆炸
    emit boardChanged();
    emit capturedChanged(m_blackCaps, m_whiteCaps);
    if (captured) m_lastCapture = QPoint(r, c);
    else m_lastCapture = QPoint(-1, -1);
    
    // 切换回合
    if (doSwitchTurn) {
        switchTurn();
    }
    return true;
}

// 新增无参数的playStone方法，使用内部回合状态
bool GoLogic::playStone(int r, int c) {
    return playStone(r, c, m_isBlackTurn, true); // 使用当前回合颜色并切换回合
}

// 切换回合的辅助方法
void GoLogic::switchTurn() {
    m_isBlackTurn = !m_isBlackTurn;
    emit turnChanged();
}

bool GoLogic::hasLiberty(int r, int c, Color col, QSet<int>& vis) const {
    int idx = index(r, c);
    if (vis.contains(idx)) return false;
    vis.insert(idx);
    for (auto [dr, dc] : {QPoint(1,0), QPoint(-1,0), QPoint(0,1), QPoint(0,-1)}) {
        int nr = r + dr, nc = c + dc;
        if (!inBounds(nr, nc)) continue;
        int nidx = index(nr, nc);
        if (m_board[nidx] == Color::Empty) return true;
        if (m_board[nidx] == col && hasLiberty(nr, nc, col, vis)) return true;
    }
    return false;
}

void GoLogic::removeGroup(int r, int c, Color col) {
    int idx = index(r, c);
    if (m_board[idx] != col) return;
    m_board[idx] = Color::Empty;
    col == Color::Black ? ++m_whiteCaps : ++m_blackCaps;
    for (auto [dr, dc] : {QPoint(1,0), QPoint(-1,0), QPoint(0,1), QPoint(0,-1)}) {
        int nr = r + dr, nc = c + dc;
        if (inBounds(nr, nc)) {  // 添加边界检查
            removeGroup(nr, nc, col);
        }
    }
}

void GoLogic::undo() {
    if (m_history.size() <= 1) return;
    m_history.pop_back();
    m_board = m_history.last();
    emit boardChanged();
    emit capturedChanged(m_blackCaps, m_whiteCaps);
}

QString GoLogic::score() const {
    // 简单形势判断：以邻接控制近似地盘，加入提子数
    int bTerr = 0, wTerr = 0;
    for (int r = 0; r < m_size; ++r) {
        for (int c = 0; c < m_size; ++c) {
            if (m_board[index(r, c)] != Color::Empty) continue;
            int b = 0, w = 0;
            for (auto [dr, dc] : {QPoint(1,0), QPoint(-1,0), QPoint(0,1), QPoint(0,-1)}) {
                int nr = r + dr, nc = c + dc;
                if (!inBounds(nr, nc)) continue;
                if (m_board[index(nr, nc)] == Color::Black) b++;
                else if (m_board[index(nr, nc)] == Color::White) w++;
            }
            if (b > w) bTerr++; else if (w > b) wTerr++;
        }
    }
    int blackScore = bTerr + m_blackCaps;
    int whiteScore = wTerr + m_whiteCaps;

    // 贴目：黑棋贴7.5目
    const double komi = 7.5;
    double delta = blackScore - whiteScore - komi;

    if (delta > 0)
        return QString("形势：黑领先 %1 目").arg(delta, 0, 'f', 1);
    else if (delta < -0.1)  // 避免浮点误差
        return QString("形势：白领先 %1 目").arg(-delta, 0, 'f', 1);
    else
        return QString("形势：双方持平");
}

int GoLogic::scoreDelta() const {
    int bTerr = 0, wTerr = 0;
    for (int r = 0; r < m_size; ++r) {
        for (int c = 0; c < m_size; ++c) {
            if (m_board[index(r, c)] != Color::Empty) continue;
            int b = 0, w = 0;
            for (auto [dr, dc] : {QPoint(1,0), QPoint(-1,0), QPoint(0,1), QPoint(0,-1)}) {
                int nr = r + dr, nc = c + dc;
                if (!inBounds(nr, nc)) continue;
                if (m_board[index(nr, nc)] == Color::Black) b++;
                else if (m_board[index(nr, nc)] == Color::White) w++;
            }
            if (b > w) bTerr++; else if (w > b) wTerr++;
        }
    }
    int blackScore = bTerr + m_blackCaps;
    int whiteScore = wTerr + m_whiteCaps;
    return blackScore - whiteScore; // 正=黑领先，负=白领先
}

QString GoLogic::finalScore() const {
    // 计算双方目数
    int bTerr = 0, wTerr = 0;
    for (int r = 0; r < m_size; ++r) {
        for (int c = 0; c < m_size; ++c) {
            if (m_board[index(r, c)] != Color::Empty) continue;
            int b = 0, w = 0;
            for (auto [dr, dc] : {QPoint(1,0), QPoint(-1,0), QPoint(0,1), QPoint(0,-1)}) {
                int nr = r + dr, nc = c + dc;
                if (!inBounds(nr, nc)) continue;
                if (m_board[index(nr, nc)] == Color::Black) b++;
                else if (m_board[index(nr, nc)] == Color::White) w++;
            }
            if (b > w) bTerr++; else if (w > b) wTerr++;
        }
    }

    int blackScore = bTerr + m_blackCaps;
    int whiteScore = wTerr + m_whiteCaps;

    // 贴目：黑棋贴7.5目
    const double komi = 7.5;
    double delta = blackScore - whiteScore - komi;

    if (delta > 0) {
        return QString("黑胜 %1 目").arg(delta, 0, 'f', 1);
    } else if (delta < 0) {
        return QString("白胜 %1 目").arg(-delta, 0, 'f', 1);
    } else {
        // 由于贴目是7.5，理论上不会出现和棋
        return QString("和棋");
    }
}
